package rsee.com;

import java.util.Iterator;
import java.util.LinkedList;

import rsee.com.EyeFrameData.FrameType;



import android.os.SystemClock;
import android.util.Log;

public class EyeFrameQueue {
	private static final int MaxFrameCount = 80;
	private static final int DefFrameRate = 15;
	private static final int DropDuration = 3000;
	private LinkedList<EyeFrameData> mQueue = null;
	private EyeFrameData mFirstFrameI = null;
	private EyeFrameData mLastFrameI = null;
	private int mFrameRate = DefFrameRate; // default
	private long mDecodeStamp = 0;
	private int mDecodedCount = 0;
	private int QueueId = 0;
	
	public int QueueId()
	{
		return QueueId;
	}
	public void setQueueId(int mQueueId)
	{
		QueueId = mQueueId;
	}
	public int getQueueId()
	{
		return QueueId;
	}
	public EyeFrameQueue() {
		mQueue = new LinkedList<EyeFrameData>();
	}

	public void dropFrame() {
		if (0 == mDecodeStamp) {
			mDecodeStamp = SystemClock.elapsedRealtime();
			mDecodedCount = 0;
			return;
		}

		int frameCount = mQueue.size();
		if (0 >= frameCount)
			return;

		long nowStamp = SystemClock.elapsedRealtime();
		long timeDuration = nowStamp - mDecodeStamp;
		long frameDuration = mDecodedCount * 1000 / mFrameRate;
		long duration = timeDuration - frameDuration;
		boolean needDrop = false;

		while (duration >= DropDuration || frameCount > MaxFrameCount) {
			Log.v("EyeFrameQueue", "dropFrame");
			needDrop = true;

			int dropCount = dropToNextFrameI();
			if (0 >= dropCount)
				break;

			long dropDuration = dropCount * 1000 / mFrameRate;
			duration -= dropDuration;
			mDecodeStamp += dropDuration;
			frameCount = mQueue.size();
		}

		if (needDrop) {
			// Runtime.getRuntime().gc();
			mDecodeStamp = nowStamp;
			mDecodedCount = 0;
		}
	}

	public void put(FrameType type, byte[] frameData, byte channelId) {
		if (null == frameData)
			return;

		EyeFrameData frame = new EyeFrameData(type, frameData, channelId);
		mQueue.add(frame);

		if (type == FrameType.FrameI) {
			if (null == mFirstFrameI){
				mFirstFrameI = frame;
				//Log.e("EyeFrameQueue", "put mFirstFrameI");
			}
			mLastFrameI = frame;
		}
	}

	public EyeFrameData get() {
		int count = mQueue.size();
		//Log.e("Frame size", ""+count);
		if (count <= 0)
			return null;

		EyeFrameData frame = mQueue.removeFirst();
		if (null == frame)
			return null;

		if (frame == mLastFrameI) {
			mFirstFrameI = mLastFrameI = null;
		} else if (frame == mFirstFrameI) {
			resetFirstFrameI();
		}

		mDecodedCount++;
		return frame;
	}

	public void setFrameRate(int val) {
		mFrameRate = val;

		if (mFrameRate <= 0)
			mFrameRate = DefFrameRate;
	}

	public int getFrameDelayMills() {
		assert (mFrameRate > 0);
		int delay = (1000 / mFrameRate);
		return delay;
	}

	public void clear() {
		mFirstFrameI = mLastFrameI = null;
		mQueue.clear();
		mFrameRate = DefFrameRate;
		mDecodedCount = 0;
		mDecodeStamp = 0;
	}

	public int dropToNextFrameI() {
		if (null == mFirstFrameI)
			return 0;

		int index = mQueue.indexOf(mFirstFrameI);
		if (0 == index) {
			if (mFirstFrameI == mLastFrameI)
				return 0;

			mQueue.removeFirst();
			index = resetFirstFrameI();
		}

		for (int i = 0; i < index; i++)
			mQueue.removeFirst();

		return index;
	}

	public int dropToLastFrameI() {
		if (null == mLastFrameI)
			return 0;

		int index = mQueue.indexOf(mLastFrameI);
		if (0 == index)
			return 0;

		index = mQueue.indexOf(mLastFrameI);
		for (int i = 0; i < index; i++)
			mQueue.removeFirst();

		mFirstFrameI = mLastFrameI;
		return index;
	}

	private int resetFirstFrameI() {
		int index = -1;
		mFirstFrameI = null;

		Iterator<EyeFrameData> iter = mQueue.iterator();
		for (; iter.hasNext();) {
			index++;
			EyeFrameData frame = iter.next();
			if (frame.getType() == FrameType.FrameI) {
				mFirstFrameI = frame;
				break;
			}
		}

		return index;
	}
}
